
package com.hlkj.pay.service.order.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.util.List;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hlkj.framework.common.pojo.PageResult;
import com.hlkj.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.hlkj.pay.common.constants.RedisConstants;
import com.hlkj.pay.dto.order.OrderPageStatisticsDto;
import com.hlkj.pay.dto.order.PayOrderQueryDto;
import com.hlkj.pay.dto.order.RouterOrderDataDto;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.infrastructure.mapper.order.OrderFeeResultMapper;
import com.hlkj.pay.infrastructure.mapper.order.OrderStatisticsMapper;
import com.hlkj.pay.infrastructure.mapper.order.PayOrderMapper;
import com.hlkj.pay.infrastructure.model.order.OrderFeeResultDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.service.CommonSnFilterService;
import com.hlkj.pay.service.order.IPayOrderService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/10/10 15:22
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class OrderServiceImpl extends CommonSnFilterService implements IPayOrderService {

    private final PayOrderMapper payOrderMapper;
    private final OrderFeeResultMapper orderFeeResultMapper;
    private final OrderStatisticsMapper orderStatisticsMapper;

    @Override
    public void addPayOrder(PayOrderDO payOrderDO) {
        payOrderMapper.insert(payOrderDO);
    }

    @Override
    public PayOrderDO queryPayOrder(PayOrderQueryDto payOrderQueryDto) {
        return payOrderMapper.selectOne(buildWrapper(payOrderQueryDto));
    }

    @Override
    @Cacheable(value = RedisConstants.PAY_ORDER_INFO, key = "#payOrderNo", unless = "#result == null")
    public PayOrderDO queryPayOrder(String payOrderNo) {
        return payOrderMapper.selectOne(PayOrderDO::getPayOrderNo, payOrderNo);
    }

    @Override
    @Cacheable(value = RedisConstants.PAY_ORDER_INFO, key = "#insOrderNo", unless = "#result == null")
    public PayOrderDO queryPayOrderByInsOrderNo(String insOrderNo) {
        return payOrderMapper.selectOne(PayOrderDO::getInsOrderNo, insOrderNo);
    }

    @Override
    @Cacheable(value = RedisConstants.PAY_ORDER_INFO, key = "#channelOrderNo", unless = "#result == null")
    public PayOrderDO queryPayOrderByChannelOrderNo(String channelOrderNo) {
        return payOrderMapper.selectOne(PayOrderDO::getChannelOrderNo, channelOrderNo);
    }

    @Override
    @Cacheable(value = RedisConstants.PAY_ORDER_INFO, key = "#sn", unless = "#result == null")
    public PayOrderDO queryPayOrderBySn(String sn) {
        return payOrderMapper.selectOne(PayOrderDO::getSn, sn);
    }

    @Override
    @Cacheable(value = RedisConstants.PAY_ORDER_INFO, key = "#autCode", unless = "#result == null")
    public PayOrderDO queryPayOrderByAutCode(String autCode) {
        return payOrderMapper.selectOne(PayOrderDO::getAutCode, autCode);
    }

    @Override
    @Cacheable(value = RedisConstants.PAY_ORDER_INFO, key = "#mchOrderNo", unless = "#result == null")
    public PayOrderDO queryPayOrderByMchOrderNo(String mchOrderNo) {
        return payOrderMapper.selectOne(PayOrderDO::getMchOrderNo, mchOrderNo);
    }

    @Override
    public PayOrderDO queryPayOrderNoCache(String payOrderNo) {
        return payOrderMapper.selectOne(PayOrderDO::getPayOrderNo, payOrderNo);
    }

    @Override
    public PayOrderDO queryWxAssociatedOrder(String transactionId) {
        PayOrderDO payOrderDO = queryPayOrder(transactionId);
        if(payOrderDO == null){
            payOrderDO = queryPayOrderByInsOrderNo(transactionId);
            if(payOrderDO == null){
                payOrderDO = queryPayOrderByChannelOrderNo(transactionId);
                if(payOrderDO == null){
                    payOrderDO = queryPayOrderByMchOrderNo(transactionId);
                }
            }
        }
        // LambdaQueryWrapperX<PayOrderDO> queryWrapper = new LambdaQueryWrapperX<>();
        // queryWrapper.and(wapper -> wapper.eq(PayOrderDO::getPayOrderNo, transactionId)
        //                             .or().eq(PayOrderDO::getMchOrderNo, transactionId)
        //                             .or().eq(PayOrderDO::getInsOrderNo, transactionId)
        //                             .or().eq(PayOrderDO::getChannelOrderNo, transactionId)
        //                             .or().eq(PayOrderDO::getChannelOrderId, transactionId)
        //
        // );
        return payOrderDO;
    }

    @Override
    @Cacheable(value = RedisConstants.PAY_ORDER_INFO_SN, key = "#sn+'_'+#merOrderNo", unless = "#result == null")
    public PayOrderDO queryPayOrderByMerOrderNo(String sn, String merOrderNo) {
        return payOrderMapper.selectOne(PayOrderDO::getSn, sn, PayOrderDO::getMchOrderNo, merOrderNo);
    }

    @Override
    public void updatePayOrder(PayOrderDO updatePayOrderDO) {
        payOrderMapper.updateById(updatePayOrderDO);
    }

    @Override
    @Caching(evict = { @CacheEvict(value = RedisConstants.PAY_ORDER_INFO, key = "#payOrderNo"),
            @CacheEvict(value = RedisConstants.PAY_ORDER_INFO_SN, key = "#sn+'_'+#merOrderNo"), })
    public void updatePayOrder(PayOrderDO updatePayOrderDO, String payOrderNo, String sn, String merOrderNo) {
        payOrderMapper.updateById(updatePayOrderDO);
    }
    @Override
    @Caching(evict = { @CacheEvict(value = RedisConstants.PAY_ORDER_INFO, key = "#payOrderNo"),
            @CacheEvict(value = RedisConstants.PAY_ORDER_INFO_SN, key = "#sn+'_'+#merOrderNo"), })
    public int updatePayOrderStatus(PayOrderDO updatePayOrderDO, String payOrderNo, String sn, String merOrderNo) {
        LambdaQueryWrapperX<PayOrderDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eqIfPresent(PayOrderDO::getId, updatePayOrderDO.getId());
        queryWrapper.ne(PayOrderDO::getState, updatePayOrderDO.getState());
        return payOrderMapper.update(updatePayOrderDO,queryWrapper);
    }

    @Override
    public PageResult<PayOrderDO> queryPage(PayOrderQueryDto payOrderQueryDto) {
        return payOrderMapper.selectPage(payOrderQueryDto, buildWrapper(payOrderQueryDto));
    }

    @Override
    public List<PayOrderDO> queryList(PayOrderQueryDto payOrderQueryDto) {
        return payOrderMapper.selectList(buildWrapper(payOrderQueryDto));
    }

    @Override
    public Integer orderCount(PayOrderQueryDto payOrderQueryDto) {
        return payOrderMapper.selectCount(buildWrapper(payOrderQueryDto)).intValue();
    }

    @Override
    public void addOrderFeeResult(OrderFeeResultDO orderFeeResultDO) {
        orderFeeResultMapper.insert(orderFeeResultDO);
    }

    @Override
    public void closePayOrder(PayOrderDO payOrderDO) {
        PayOrderDO updatePayOrderDO = new PayOrderDO();
        updatePayOrderDO.setId(payOrderDO.getId());
        updatePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.CLOSE.getCode());
        payOrderDO.setState(updatePayOrderDO.getState());
        updatePayOrder(updatePayOrderDO, payOrderDO.getPayOrderNo(), payOrderDO.getOrderSn(), payOrderDO.getMchOrderNo());
    }

    @Override
    public OrderPageStatisticsDto queryStaticOrdersPage(PayOrderQueryDto payOrderQueryDto) {
        return orderStatisticsMapper.queryStaticOrdersPage(payOrderQueryDto);
    }

    @Override
    public RouterOrderDataDto querySuccessOrder(PayOrderQueryDto payOrderQueryDto) {
        return orderStatisticsMapper.querySuccessOrder(buildWrapper(payOrderQueryDto));
    }

    @Override
    public RouterOrderDataDto querySuccessOrderAmount(PayOrderQueryDto payOrderQueryDto) {
        return orderStatisticsMapper.querySuccessOrderAmount(buildWrapper(payOrderQueryDto));
    }

    /**
     * 查询条件封装
     *
     * @param payOrderQueryDto
     * @return
     */
    LambdaQueryWrapper<PayOrderDO> buildWrapper(PayOrderQueryDto payOrderQueryDto) {
        filterSn(payOrderQueryDto);
        LambdaQueryWrapperX<PayOrderDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eqIfPresent(PayOrderDO::getPayOrderNo, payOrderQueryDto.getPayOrderNo());
        queryWrapper.eqIfPresent(PayOrderDO::getMchOrderNo, payOrderQueryDto.getMchOrderNo());
        queryWrapper.eqIfPresent(PayOrderDO::getInsOrderNo, payOrderQueryDto.getInsOrderNo());
        queryWrapper.eqIfPresent(PayOrderDO::getChannelOrderNo, payOrderQueryDto.getChannelOrderNo());
        queryWrapper.eqIfPresent(PayOrderDO::getChannelOrderId, payOrderQueryDto.getChannelOrderId());
        queryWrapper.eqIfPresent(PayOrderDO::getState, payOrderQueryDto.getState());
        queryWrapper.inIfPresent(PayOrderDO::getState, payOrderQueryDto.getStates());
        queryWrapper.eqIfPresent(PayOrderDO::getAppId, payOrderQueryDto.getAppId());
        queryWrapper.eqIfPresent(PayOrderDO::getProviderCode, payOrderQueryDto.getProviderCode());
        queryWrapper.eqIfPresent(PayOrderDO::getChannelCode, payOrderQueryDto.getChannelCode());
        queryWrapper.eqIfPresent(PayOrderDO::getPayType, payOrderQueryDto.getPayType());
        queryWrapper.eqIfPresent(PayOrderDO::getPaySubType, payOrderQueryDto.getPaySubType());
        queryWrapper.eqIfPresent(PayOrderDO::getPayWayCode, payOrderQueryDto.getPayWayCode());
        queryWrapper.inIfPresent(PayOrderDO::getOrderSn, payOrderQueryDto.getSnList());
        queryWrapper.eqIfPresent(PayOrderDO::getOrderSn, payOrderQueryDto.getSn());
        queryWrapper.eqIfPresent(PayOrderDO::getNotifyState, payOrderQueryDto.getNotifyState());
        queryWrapper.eqIfPresent(PayOrderDO::getFundProcessType, payOrderQueryDto.getFundProcessType());
        queryWrapper.eqIfPresent(PayOrderDO::getRefundStatus, payOrderQueryDto.getRefundStatus());
        queryWrapper.likeIfPresent(PayOrderDO::getSubMchId, payOrderQueryDto.getSubMchId());
        queryWrapper.eqIfPresent(PayOrderDO::getSceneType, payOrderQueryDto.getSceneType());
        queryWrapper.eqIfPresent(PayOrderDO::getAutCode, payOrderQueryDto.getAutCode());
        queryWrapper.eqIfPresent(PayOrderDO::getAtuSubMerId, payOrderQueryDto.getAtuSubMerId());
        queryWrapper.eqIfPresent(PayOrderDO::getMchChannelCode, payOrderQueryDto.getMchChannelCode());

        queryWrapper.eqIfPresent(PayOrderDO::getRelationOrderNo, payOrderQueryDto.getRelationOrderNo());
        queryWrapper.eqIfPresent(PayOrderDO::getOrderType, payOrderQueryDto.getOrderType());

        queryWrapper.geIfPresent(PayOrderDO::getAmount, payOrderQueryDto.getMinAmount());
        queryWrapper.leIfPresent(PayOrderDO::getAmount, payOrderQueryDto.getMaxAmount());
        queryWrapper.geIfPresent(PayOrderDO::getCreateTime, payOrderQueryDto.getStartQueryTime());
        queryWrapper.leIfPresent(PayOrderDO::getCreateTime, payOrderQueryDto.getEndQueryTime());
        queryWrapper.leIfPresent(PayOrderDO::getExpiredTime, payOrderQueryDto.getMaxExpiredTime());
        return queryWrapper;
    }
}
